/*
 *    Copyright 2009-2023 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.ryan.builder;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.ryan.Tools;
import org.apache.ibatis.ryan.utils.PageHoder;

public class NativeSQLBuilder {
    // sql 字符串池
    private StringBuilder sql = new StringBuilder("");
    // 参数前缀
    public static String param3 = "param3.";
    // 匹配变量
    private static Pattern varToken = Pattern.compile("#\\{([\\w.]+)\\}");
    private Class<?> resultType;
    // 参数
    private Map<String, Object> params = new HashMap<>();

    private NativeSQLBuilder(Class<?> resultType) {
        if (resultType == null) {
            throw new IllegalArgumentException("resultType can not  be null!");
        }
        this.resultType = resultType;
    }

    /**
     * 构建查询对象
     *
     * @param resultType 查询返回对象类型
     * @return
     */
    public static NativeSQLBuilder build(Class<?> resultType) {
        return new NativeSQLBuilder(resultType);
    }

    /**
     * 根据构建条件拼接出sql
     *
     * @return
     */
    public String buildSql() {
        String sql = this.sql.toString();
        if (StringUtils.isBlank(sql.toString())) {
            throw new IllegalArgumentException("sql can not  be null!");
        }
        // 将参数占位符 替换掉
        sql = sql.replaceAll(param3, "");
        // 处理参数占位符
        Matcher matcher = varToken.matcher(sql);
        while (matcher.find()) {
            String group = matcher.group(1);
            System.out.println("处理key=" + group);
            String key = param3 + group.replace(".", "_");
            sql = sql.replace(matcher.group(0), "#{" + key + "}");
        }
        return sql;
    }

    /**
     * 直接设置SQL
     *
     * @param sql
     * @return
     */
    public NativeSQLBuilder setSql(String sql) {
        this.sql = new StringBuilder(sql);
        return this;
    }

    /**
     * 如果查询条件值不为空
     * 添加查询条件 sql 字符串
     * 例子: appendIfOpt(" a = #{xxx} ","xxx",123)
     *
     * @param sql
     * @param mybatisKey
     * @param value
     * @return
     */
    public NativeSQLBuilder appendIfOpt(String sql, String mybatisKey, Object value) {
        if (value == null || StringUtils.isBlank(value.toString())) {
            return this;
        }
        this.sql.append(" ").append(sql);
        setValue(mybatisKey, value);
        return this;
    }

    /**
     * 添加查询条件 sql 字符串
     * append(" a = #{xxx} ","xxx",123)
     *
     * @param sql
     * @return
     */
    public NativeSQLBuilder append(String sql) {
        this.sql.append(" ").append(sql);
        return this;
    }

    /**
     * 获取返回类型
     *
     * @return
     */
    public Class getResultType() {
        return this.resultType;
    }

    /**
     * 获取参数列表
     *
     * @return
     */
    public Map<String, Object> getParams() {
        return this.params;
    }

    /**
     * 添加查询条件参数
     *
     * @param mybatisKey
     * @param value
     * @return
     */
    public NativeSQLBuilder setValue(String mybatisKey, Object value) {
        // 如果是日期查询条件先转成 字符串
        value = Tools.formatIfDate(value);

        // 把 . 替换成下划线
        String key = mybatisKey.replace(".", "_");
        this.params.put(key, value);
        return this;
    }

    /**
     * 根据对象bean和表名称进行SQL构建
     *
     * @param <W>
     * @param whereBean
     * @param table
     * @return
     */
    public <W> NativeSQLBuilder whereBean(W whereBean, String table) {
        if (whereBean == null) {
            return this;
        }
        List<Field> fields = Tools.getInstanceFields(whereBean.getClass());
        if (fields.isEmpty()) {
            return this;
        }

        fields.forEach(field -> {
            Object fieldValue = Tools.getFieldValue(whereBean, field);
            String pre = (table != null) ? table : Tools.tableName(whereBean.getClass());
            setValue(pre + "." + field.getName(), fieldValue);
        });
        return this;
    }

    /**
     * 分页参数设置
     *
     * @param pageNo
     * @param pageSize
     */
    public void setPage(int pageNo, int pageSize) {
        PageHoder.setPageNo(Integer.valueOf(pageNo));
        PageHoder.setPageSize(Integer.valueOf(pageSize));
    }

    public String getSql() {
        return buildSql();
    }
}
